// ##########################################################################
// #                                                                        #
// #                              CLOUDCOMPARE                              #
// #                                                                        #
// #  This program is free software; you can redistribute it and/or modify  #
// #  it under the terms of the GNU General Public License as published by  #
// #  the Free Software Foundation; version 2 or later of the License.      #
// #                                                                        #
// #  This program is distributed in the hope that it will be useful,       #
// #  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
// #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
// #  GNU General Public License for more details.                          #
// #                                                                        #
// #          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
// #                                                                        #
// ##########################################################################

#ifndef CC_INDEXED_TRANSFORMATION_BUFFER_HEADER
#define CC_INDEXED_TRANSFORMATION_BUFFER_HEADER

// Local
#include "ccHObject.h"
#include "ccIndexedTransformation.h"

// system
#include <cfloat>

//! Indexed Transformation buffer
class QCC_DB_LIB_API ccIndexedTransformationBuffer : public ccHObject
    , public std::vector<ccIndexedTransformation>
{
  public:
	//! Default constructor
	ccIndexedTransformationBuffer(const QString& name = QString("Trans. buffer"));
	//! Copy constructor
	ccIndexedTransformationBuffer(const ccIndexedTransformationBuffer& buffer);

	// inherited from ccHObject
	CC_CLASS_ENUM getClassID() const override
	{
		return CC_TYPES::TRANS_BUFFER;
	}
	bool isSerializable() const override
	{
		return true;
	}

	//! Sorts transformations based on their index
	/** Ascending sort.
	 **/
	void sort();

	//! Returns the nearest indexed transformation(s) to a given index
	/** This method returns the preceding and following transformations.

	    \warning Binary search: buffer must be sorted! (see ccIndexedTransformationBuffer::sort)

	    \param index query index (e.g. timestamp)
	    \param trans1 directly preceding transformation (if any - null otherwise)
	    \param trans2 directly following transformation (if any - null otherwise)
	    \param trans1IndexInBuffer (optional) index of trans1 in buffer
	    \param trans2IndexInBuffer (optional) index of trans2 in buffer
	    \return success
	**/
	bool findNearest(double                          index,
	                 const ccIndexedTransformation*& trans1,
	                 const ccIndexedTransformation*& trans2,
	                 size_t*                         trans1IndexInBuffer = nullptr,
	                 size_t*                         trans2IndexInBuffer = nullptr) const;

	//! Returns the indexed transformation at a given index (interpolates it if necessary)
	/** \warning Binary search: buffer must be sorted! (see ccIndexedTransformationBuffer::sort)

	    \param index query index (e.g. timestamp)
	    \param trans output transformation (if successful)
	    \param maxIndexDistForInterpolation max 'distance' between query index and existing indexes to actually interpolate/output a transformation
	    \return success
	**/
	bool getInterpolatedTransformation(double                   index,
	                                   ccIndexedTransformation& trans,
	                                   double                   maxIndexDistForInterpolation = DBL_MAX) const;

	//! [Display option] Returns whether trihedrons should be displayed or not (otherwise only points or a polyline)
	bool trihedronsShown() const
	{
		return m_showTrihedrons;
	}
	//! [Display option] Sets whether trihedrons should be displayed or not (otherwise only points or a polyline)
	void showTrihedrons(bool state)
	{
		m_showTrihedrons = state;
	}

	//! [Display option] Returns trihedron display size
	float trihedronsDisplayScale() const
	{
		return m_trihedronsScale;
	}
	//! [Display option] Sets trihedron display size
	void setTrihedronsDisplayScale(float scale)
	{
		m_trihedronsScale = scale;
	}

	//! [Display option] Returns whether the path should be displayed as a polyline or not (otherwise only points)
	bool isPathShownAsPolyline() const
	{
		return m_showAsPolyline;
	}
	//! [Display option] Sets whether the path should be displayed as a polyline or not (otherwise only points)
	void showPathAsPolyline(bool state)
	{
		m_showAsPolyline = state;
	}

	//! Invalidates the bounding box
	/** Should be called whenever the content of this structure changes!
	 **/
	void invalidateBoundingBox();

	// Inherited from ccHObject
	ccBBox getOwnBB(bool withGLFeatures = false) override;

  protected:
	// inherited from ccHObject
	bool  toFile_MeOnly(QFile& out, short dataVersion) const override;
	bool  fromFile_MeOnly(QFile& in, short dataVersion, int flags, LoadedIDMap& oldToNewIDMap) override;
	short minimumFileVersion_MeOnly() const override;
	void  drawMeOnly(CC_DRAW_CONTEXT& context) override;

	//! Bounding box
	ccBBox m_bBox;
	//! Bounding box last 'validity' size
	size_t m_bBoxValidSize;

	//! Whether the path should be displayed as a polyline or not
	bool m_showAsPolyline;
	//! Whether trihedrons should be displayed or not
	bool m_showTrihedrons;
	//! Trihedrons display scale
	float m_trihedronsScale;
};

#endif
